home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / language / awe / awe-full.lha / Awe2 / DoNotUseThisSrc / NewRandom < prev    next >
Text File  |  1989-11-29  |  47KB  |  1,588 lines

  1. (Message inbox:3183)
  2. Return-Path: SRWMRBD@WNV.DSIR.GOVT.NZ
  3. Received: from truth.waikato.ac.nz by june.cs.washington.edu (5.61/7.0j)
  4.     id AA06839; Thu, 31 Aug 89 19:38:53 -0700
  5. Message-Id: <8909010238.AA06839@june.cs.washington.edu>
  6. Received: from wnv.dsir.govt.nz by waikato.ac.nz; Fri, 1 Sep 89 14:07 +1200
  7. Date: Fri, 1 Sep 89 14:09 NZST
  8. From: ROBERT <SRWMRBD@WNV.DSIR.GOVT.NZ>
  9. Subject: RE: Re: random number package
  10. To: sullivan@june.cs.washington.EDU
  11. X-Vms-To: IN%"sullivan@june.cs.washington.EDU",SRWMRBD
  12.  
  13. RANDOM NUMBER GENERATOR PACKAGE
  14.  
  15.  
  16. Copyright (C) 1989: R B Davies and DSIR
  17.  
  18. Permission is granted to use or distribute but not to sell.
  19.  
  20. The gamma function routine is adapted from "Numerical Recipies in C" by Press,
  21. Flannery, Teukolsky, Vetterling published by the Cambridge University Press.
  22.  
  23. This is a package for generating sequences of random numbers from a wide
  24. variety of distributions. It is particularly appropriate for the situation
  25. where one requires sequences of identically distributed random numbers since
  26. the set up time for each type of distribution is relatively long but it is
  27. very efficient for generating each new random number. The package includes
  28. "classes" for generating random numbers from a number of distributions, but is
  29. easily extended to be able to generate random numbers from almost any of the
  30. standard distributions.
  31.  
  32. The following table shows the classes included in the package.
  33.  
  34.  
  35. CLASS STRUCTURE:
  36.  
  37. ExtReal.......................... "Extended real numbers"
  38.  
  39. Random........................... Uniform random number generator
  40.  |
  41.  +---Constant.................... Return a constant
  42.  |
  43.  +---PosGen...................... Used by PosGenX etc
  44.  |    |
  45.  |    +---PosGenX................ Positive random #s from decreasing density
  46.  |    |
  47.  |    +---Exponential............ Negative exponential rng
  48.  |    |
  49.  |    +---Gamma1................. Used by Gamma (shape parameter < 1)
  50.  |    |
  51.  |    +---SymGen................. Used by SymGenX etc
  52.  |         |
  53.  |         +---SymGenX........... Random #s from symmetric density
  54.  |         |
  55.  |         +---Cauchy............ Cauchy random number generator
  56.  |         |
  57.  |         +---Normal............ Standard normal random number generator
  58.  |              |
  59.  |              +---ChiSq1....... Used by ChiSq (one df)
  60.  |          
  61.  +---AsymGen..................... Used by AsymGenX etc
  62.  |    |
  63.  |    +---AsymGenX............... Random #s from asymmetric density
  64.  |    |
  65.  |    +---Poisson1............... Used by Poisson (mean > 10)
  66.  |    |
  67.  |    +---Gamma2................. Used by Gamma (shape parameter > 1)
  68.  |
  69.  +---ChiSq....................... Non-central chi-squared rng
  70.  |
  71.  +---Gamma....................... Gamma random number generator
  72.  |
  73.  +---DiscreteGen................. Discrete random number generator
  74.  |
  75.  +---Poisson2.................... Used by Poisson (mean <= 10)
  76.  |
  77.  +---Poisson..................... Poisson random number generator
  78.  |
  79.  +---SumRandom................... Sum of random numbers
  80.  |
  81.  +---MixedRandom................. Mixture of random numbers
  82.  |
  83.  +---AddedRandom................. Used by SumRandom and MixedRandom
  84.  |
  85.  +---SubtedRandom................ Used by SumRandom
  86.  |
  87.  +---MultedRandom................ Used by SumRandom
  88.  |
  89.  +---ShiftedRandom............... Used by SumRandom
  90.  |
  91.  +---ScaledRandom................ Used by SumRandom
  92.  |
  93.  +---RepeatedRandom.............. Used by SumRandom
  94.  |
  95.  +---SelectedRandom.............. Used by MixedRandom
  96.  
  97.  
  98. Each of the classes includes the following functions:
  99.  
  100. void Set(double) ................ Set seed (inherited from base class)
  101. double Get() .................... Get seed (inherited from base class)
  102. real Next() ..................... Get a new random number
  103. char* Name() .................... Name of the distribution
  104. ExtReal Mean() .................. Mean of the distribution
  105. ExtReal Variance() .............. Variance of the distribution
  106.  
  107. plus the class constructor(s).
  108.  
  109. Set(double) must be called for just one class with an argument between 0 and 1
  110. to set up the base random number generator before Next() is called in any
  111. class.
  112.  
  113. The package can be run in single precision or double precision; "real" must be
  114. defined as "float" or "double" by typedef statement. The Mean() and Variance()
  115. functions use "extended reals" so the ExtReal package must be included.
  116.  
  117.  
  118. NOW DESCRIBING THE INDIVIDUAL CLASSES AND SKETCHING THE METHODS THEY USE:
  119.  
  120. Random:
  121. ------
  122. This is the basic uniform random number generator, used to drive all the
  123. others. The Lewis-Goodman-Miller algorithm is used followed by Marsaglia
  124. mixing using the C random number generator. While not perfect, and probably
  125. superceded, the LGM generator has given me acceptable results in a wide
  126. variety of simulations. Ideally the basic generator should be recoded in
  127. assembly language to give the maximum speed to all the generators in this
  128. package.
  129.  
  130. The constructor has no parameters. For example
  131.  
  132. Random U;
  133. for (int i=0; i<100; i++) cout << U.Next() << "\n";
  134.  
  135.  
  136. Constant:
  137. --------
  138. This returns a constant. The constructor takes one "real" parameter; the value
  139. of the constant to be returned.
  140.  
  141.  
  142. PosGen:
  143. ------
  144. PosGen is not used directly. It is used as a base class for generating a
  145. random number from an arbitrary probability density p(x). p(x) must be
  146. non-zero only for x>=0, be monotonically decreasing for x>=0, and be finite.
  147. For example, p(x) could be exp(-x) for x>=0.
  148.  
  149. The method is to cover the density in a set of rectangles of equal area as in
  150. the diagram (indicated by ---).
  151.  
  152. |
  153. x
  154. |xx------
  155. |  xx    |
  156. |    xxx |
  157. |.......xxx---------
  158. |        | xxxx     |
  159. |        |     xxxx |
  160. |        |.........xxxxx------------
  161. |        |          |   xxxxx       |
  162. |        |          |        xxxxxx |
  163. |        |          |..............xxxxxx----------------------
  164. |        |          |               |    xxxxxxx               |
  165. |        |          |               |           xxxxxxx        |
  166. |        |          |               |                  xxxxxxxx|
  167. +===========================================================================
  168.  
  169. The numbers are generated by generating a pair of numbers uniformly
  170. distributed over these rectangles and then accepting the x coordinate as the
  171. next random number if the pair corresponds to a point below the density
  172. function. The acceptance can be done in two stages, the first being whether he
  173. number is below the dotted line. This means that the density function need be
  174. checked only very occasionally and on the average only just over 3 uniform
  175. random numbers are required for each of the random numbers produced by this
  176. generator.
  177.  
  178. See PosGenX or Exponential for the method of deriving a class to generate
  179. random numbers from a given distribution.
  180.  
  181.  
  182. PosGenX:
  183. -------
  184. This uses an arbitrary density satisfying the previous conditions to generate
  185. random numbers from that density. Suppose
  186.  
  187. real pdf(real)
  188.  
  189. is the density. Then use pdf as the argument of the constructor. For example
  190.  
  191. PosGenX P(pdf);
  192. for (int i=0; i<100; i++) cout << P.Next() << "\n";
  193.  
  194.  
  195. Exponential:
  196. -----------
  197. This generates random numbers with density exp(-x) for x>=0. The constructor
  198. takes no arguments.
  199.  
  200.  
  201. Gamma1:
  202. ------
  203. This generates random numbers from a gamma distribution with shape parameter
  204. alpha<1. Because the density is infinite at x=0 a power transform is required
  205. so this random number generator may not be as efficient as the others
  206. described here. A better method would handle the immediate neighbourhood of
  207. the origin separately and use PosGen directly for the rest. The constructor
  208. takes real alpha as an argument.
  209.  
  210.  
  211. SymGen:
  212. ------
  213. SymGen is a modification of PosGen for unimodal distributions symmetric about
  214. the origin, such as the standard normal.
  215.  
  216.  
  217. SymGenX:
  218. -------
  219. This corresponds to PosGenX for symmetric distributions.
  220.  
  221.  
  222. Cauchy:
  223. ------
  224. Generates random numbers from a standard Cauchy distribution. The constructor
  225. takes no parameters.
  226.  
  227.  
  228. Normal:
  229. ------
  230. Generates standard normal random numbers. The constructor has no arguments.
  231. This class has been slightly modified to ensure only one copy of the arrays
  232. generated by the constructor exist at any given time. That is, if the
  233. constructor is called twice (before the destructor is called) only one copy of
  234. the arrays is generated.
  235.  
  236.  
  237. ChiSq1:
  238. ------
  239. Non-central chi-squared with one degree of freedom. Used as part of ChiSq.
  240.  
  241.  
  242. AsymGen:
  243. -------
  244. A general random number generator for unimodal distributions following the
  245. method used by PosGen. The constructor takes one argument: the location of the
  246. mode of the distribution.
  247.  
  248.  
  249. AsymGenX:
  250. --------
  251. Corresponds to PosGenX. The arguments of the constructor are the name of the
  252. density function and the location of the mode.
  253.  
  254. real pdf(real);
  255. real mode;
  256. .....
  257. AsymGenX X(pdf,mode);
  258. for (int i=0; i<100; i++) cout << X.Next() << "\n";
  259.  
  260.  
  261. Poisson1:
  262. --------
  263. Poisson distribution; derived from AsymGen. The constructor takes the mean as
  264. the argument. Used by Poisson for values of the mean greater than 10.
  265.  
  266.  
  267. Gamma2:
  268. ------
  269. Gamma distribution for the shape parameter, alpha, greater than 1. The
  270. constructor takes alpha as the argument. Used by Gamma.
  271.  
  272.  
  273. ChiSq:
  274. -----
  275. Non-Central chi-squared distribution. The method uses ChiSq1 to generate the
  276. non-central part and Gamma2 or Exponential to generate the central part. The
  277. constructor takes as arguments the number of degrees of freedom (>=1) and the
  278. non-centrality parameter (omit if zero).
  279.  
  280.  
  281. Gamma:
  282. -----
  283. Gamma distribution. The constructor takes the shape parameter as argument.
  284. Uses Gamma1, Gamma2 or Exponential.
  285.  
  286.  
  287. DiscreteGen:
  288. -----------
  289. This is for generating random numbers taking just a finite number of values.
  290. There are two alternative forms of the constructor:
  291.  
  292. DiscreteGen D(n,prob);
  293. DiscreteGen D(n,prob,val);
  294.  
  295. where n is an integer giving the number of values, prob a real array of length
  296. n giving the probabilities and val a real array of length n giving the set of
  297. values that are generated. If val is omitted the values are 0,1,...,n-1.
  298.  
  299. The method requires two uniform random numbers for each number it produces.
  300. This method is described by Kronmal and Peterson, American Statistician, 1979,
  301. Vol 33, No 4, pp214-218.
  302.  
  303.  
  304. Poisson2:
  305. --------
  306. Poisson distribution with mean less than or equal to 10. Uses DiscreteGen.
  307. Constructor takes the mean as its argument.
  308.  
  309.  
  310. Poisson:
  311. -------
  312. Poisson distribution: uses Poisson1 or Poisson2. Constructor takes the mean as
  313. its argument.
  314.  
  315.  
  316. SumRandom:
  317. ---------
  318. This is for building a random number generator as a linear or multplicative
  319. combination of existing random number generators. Suppose rv1, rv2, rv3, rv4
  320. are random number generators defined with constructors given above and r1, r2,
  321. r0 are reals and i1, i3 are integers.
  322.  
  323. Then the generator S defined by
  324.  
  325. SumRandom S = rv1(i1)*r1 - rv2*r2 + rv3(i3)*rv4 + r0;
  326.  
  327. has the obvious meaning. rv1(i1) means that the sum of i1 independent values
  328. from of rv1 should be used. Note that rv1*rv1 means the product of two
  329. independent numbers generated from rv1.
  330.  
  331. Remember that this becomes a very inefficient method if the number of terms or
  332. copies is large.
  333.  
  334.  
  335. MixedRandom:
  336. -----------
  337. This is for mixtures of distributions. Suppose rv1, rv2, rv3 are random number
  338. generators and p1, p2, p3 are reals summing to 1.
  339.  
  340. Then the generator M defined by
  341.  
  342. MixedRandom M = rv1(p1) + rv2(p2) + rv3(p3);
  343.  
  344. produces a random number generator with selects its next random number from
  345. rv1 with probability p1, rv2 with probability p2, rv3 with probability p3.
  346.  
  347. Alternatively one can use the constructor
  348.  
  349. MixedRandom M(n, prob, rv);
  350.  
  351. where n is the number of distributions in the mixture, prob the real array of
  352. probabilities, rv an array of pointers to random variables.
  353.  
  354.  
  355. AddedRandom, SubtedRandom, MultedRandom, ShiftedRandom, ScaledRandom,
  356. -----------  ------------  ------------  -------------  ------------ 
  357. RepeatedRandom, SelectedRandom:
  358. --------------  --------------
  359. These are used by SumRandom and MixedRandom.
  360.  
  361.  
  362. GENERATING RANDOM NUMBERS FROM OTHER DISTRIBUTIONS:
  363.  
  364. Continuous finite unimodal density (no parameters): I assume you have a
  365. program to calculate the density. Use PosGenX, SymGenX or AsymGen.
  366. Alternatively derive a new class from PosGen, SymGen or AsymGen. Cauchy and
  367. Exponential are examples.
  368.  
  369. Continuous finite unimodal density (with parameters): Derive a new class from
  370. PosGen, SymGen or AsymGen. Gamma2 is an example.
  371.  
  372. Transformation of existing random number generator: Derive a new class from
  373. the existing class. ChiSq1 is an example.
  374.  
  375. Transformation of several random numbers: Define a new class derived from
  376. Random and generate the new random number from the existing random number
  377. generators. ChiSq is a rather complex example.
  378.  
  379. Density with infinite singularity: This may sometimes be handled by
  380. transforming a random variable generated by PosGen, SymGen or AsymGen. Gamma1
  381. is an example.
  382.  
  383. Distribution with several modes: Breakdown into a mixture of unimodal
  384. distributions.
  385.  
  386. Linear or quadratic combination of existing random numbers: Use SumRandom.
  387.  
  388. Mixture of existing random numbers: Use MixedRandom.
  389.  
  390. Discrete distribution (< 100 possible values): Use DiscreteGen. DiscreteGen
  391. and Poisson2 are examples.
  392.  
  393. Discrete distribution (many possible values): Use PosGen, SymGen or AsymGen.
  394. Poisson1 is an example.
  395.  
  396.  
  397. MAKEFILE TO COMPILE UNDER ZORTECH:
  398.  
  399. Assume that main() is in file tryrand.cxx.
  400.  
  401.  
  402. C = ztc -f -c -dZORTECH $*.cxx
  403. D = ztc -f -c -dZORTECH $*.cxx -o
  404.  
  405. OBJ = tryrand.obj random.obj extreal.obj
  406.  
  407. makefile:     tryrand.exe
  408.  
  409. tryrand.exe:  $(OBJ)
  410.               ztc -f $**
  411.  
  412. random.obj:   random.cxx extreal.hxx random.hxx
  413.               $D
  414.  
  415. extreal.obj:  extreal.cxx extreal.hxx
  416.               $D
  417.  
  418. tryrand.obj:  tryrand.cxx
  419.               $D
  420.  
  421.  
  422. FILES INCLUDED IN THIS PACKAGE:
  423.  
  424. random.tex         this file
  425. random.hxx         include file for random.cxx
  426. random.cxx         main code file
  427. extreal.hxx        include file for extreal.cxx
  428. extreal.cxx        code file for extreal package
  429. boolean.hxx        definition of boolean variable
  430.  
  431.  
  432. // random.hxx ------------------------------------------------------------
  433.  
  434.  
  435. #ifndef RANDOM_LIB
  436. #define RANDOM_LIB 0
  437.  
  438. #ifndef ZORTECH                  // for systems that won't accept long names
  439. #define AddedRandom AdRan 
  440. #define MultedRandom MuRan
  441. #define SubtedRandom SuRan
  442. #define ScaledRandom ScRan
  443. #define ShiftedRandom ShRan
  444. #define RepeatedRandom ReRan
  445. #define SelectedRandom SeRan
  446. #define SumRandom SumRan
  447. #define MixedRandom MiRan
  448. #endif
  449.  
  450.  
  451.  
  452. /******************** utilities and definitions *************************/
  453.  
  454. #include <boolean.hxx>
  455. #include <extreal.hxx> 
  456.  
  457. typedef real (*PDF)(real);                // probability density function
  458.  
  459. /***************** uniform random number generator **********************/
  460.  
  461. class AddedRandom;                        // defined later
  462. class MultedRandom;
  463. class SubtedRandom;
  464. class ScaledRandom;
  465. class ShiftedRandom;
  466. class RepeatedRandom;
  467. class SelectedRandom;
  468.  
  469. class Random                              // uniform random number generator
  470. {
  471.    static double seed;                    // seed
  472.    static real Buffer[128];               // for mixing random numbers
  473.    real Raw();                            // unmixed random numbers
  474.  
  475. protected:
  476.    virtual void Error(char*);             // error handler
  477.    virtual void ErrorNoSpace();           // nospace message
  478.  
  479. public:
  480.    void Set(double s);                    // set seed (0 < seed < 1)
  481.    double Get();                          // get seed
  482.    virtual real Next();                   // get new value
  483.    virtual char* Name();                  // identification
  484.    virtual real Density(real);            // used by PosGen & Asymgen
  485.    Random() {}                            // do nothing
  486.    virtual ~Random() {}                   // make destructors virtual
  487.    AddedRandom operator+(Random&);        // for making combinations
  488.    MultedRandom operator*(Random&);
  489.    SubtedRandom operator-(Random&);
  490.    ShiftedRandom operator+(real);
  491.    ShiftedRandom operator-(real);
  492.    ScaledRandom operator*(real);
  493.    RepeatedRandom operator()(int);
  494.    SelectedRandom operator()(double);     // used by MixedRandom
  495.    void operator=(Random);                // = (not allowed)
  496.    virtual ExtReal Mean() { return 0.5; } // mean of distribution
  497.    virtual ExtReal Variance() { return 1.0/12.0; }
  498.                                           // variance of distribution
  499.    virtual int nelems() { return 1; }     // used by MixedRandom
  500.    virtual void load(int*,real*,Random**);
  501. };
  502.  
  503. /************************** return constant ******************************/
  504.  
  505. class Constant : public Random
  506. {
  507.    real value;                            // value to be returned
  508.  
  509. public:
  510.    char* Name();                          // identification
  511.    Constant(real v) { value=v; }          // set value
  512.    real Next() { return value; }
  513.    ExtReal Mean() { return value; }
  514.    ExtReal Variance() { return 0.0; }
  515. };
  516.  
  517. /***************** positive random number generator **********************/
  518.  
  519. class PosGen : public Random              // generate positive rv
  520. {
  521. protected:
  522.    real xi, *sx, *sfx;
  523.    BOOL NotReady;
  524.    void Build(BOOL);                      // called on first call to Next
  525.  
  526. public:
  527.    char* Name();                          // identification
  528.    PosGen();                              // constructor
  529.    ~PosGen();                             // destructor
  530.    real Next();                           // to get a single new value
  531.    ExtReal Mean() { return Missing; }
  532.    ExtReal Variance() { return Missing; }
  533. };
  534.  
  535. /***************** symmetric random number generator **********************/
  536.  
  537. class SymGen : public PosGen              // generate symmetric rv
  538. {
  539.  
  540. public:
  541.    char* Name();                          // identification
  542.    real Next();                           // to get a single new value
  543. };
  544.  
  545. /***************** normal random number generator **********************/
  546.  
  547. class Normal : public SymGen              // generate standard normal rv
  548. {
  549.    static real Nxi, *Nsx, *Nsfx;          // so we need initialise only once
  550.    static long count;                     // assume initialised to 0
  551. public:
  552.    char* Name();                          // identification
  553.    Normal();
  554.    ~Normal();
  555.    real Density(real);                    // normal density function
  556.    ExtReal Mean() { return 0.0; }
  557.    ExtReal Variance() { return 1.0; }
  558. };
  559.  
  560. /************ chi-square random number generator **********************/
  561.  
  562. class ChiSq : public Random               // generate non-central chi-sq rv
  563. {
  564.    Random* c1;                            // pointers to generators
  565.    Random* c2;                            // pointers to generators
  566.    int version;                           // indicates method of generation
  567.    real mean, var;
  568.  
  569. public:
  570.    char* Name();                          // identification
  571.    ChiSq(int, real=0.0);                  // df and non-centrality parameter
  572.    ~ChiSq();
  573.    ExtReal Mean() { return mean; }
  574.    ExtReal Variance() { return var; }
  575.    real Next();
  576. };
  577.  
  578. /***************** Cauchy random number generator **********************/
  579.  
  580. class Cauchy : public SymGen              // generate standard cauchy rv
  581. {
  582. public:
  583.    char* Name();                          // identification
  584.    real Density(real);                    // Cauchy density function
  585.    ExtReal Mean() { return Indefinite; }
  586.    ExtReal Variance() { return PlusInfinity; }
  587. };
  588.  
  589. /***************** Exponential random number generator **********************/
  590.  
  591. class Exponential : public PosGen         // generate standard cauchy rv
  592. {
  593. public:
  594.    char* Name();                          // identification
  595.    real Density(real);                    // Cauchy density function
  596.    ExtReal Mean() { return 1.0; }
  597.    ExtReal Variance() { return 1.0; }
  598. };
  599.  
  600. /***************** asymmetric random number generator **********************/
  601.  
  602. class AsymGen : public Random             // generate asymmetric rv
  603. {
  604.    real xi, *sx, *sfx, mode; int ic;
  605.    BOOL NotReady;
  606.    void Build();                          // called on first call to Next
  607.  
  608. public:
  609.    char* Name();                          // identification
  610.    AsymGen(real);                         // constructor (real=mode)
  611.    ~AsymGen();                            // destructor
  612.    real Next();                           // to get a single new value
  613.    ExtReal Mean() { return Missing; }
  614.    ExtReal Variance() { return Missing; }
  615. };
  616.  
  617. /***************** Gamma random number generator **********************/
  618.  
  619. class Gamma : public Random               // generate gamma rv
  620. {
  621.    Random* method;
  622. public:
  623.    char* Name();                          // identification
  624.    Gamma(real);                           // constructor (real=shape)
  625.    ~Gamma() { delete method; }
  626.    real Next() { return method->Next(); }
  627.    ExtReal Mean() { return method->Mean(); }
  628.    ExtReal Variance() { return method->Variance(); }
  629. };
  630.  
  631. /***************** Generators with pointers to pdf ***********************/
  632.  
  633. class PosGenX : public PosGen
  634. {
  635.    PDF f;
  636. public:
  637.    char* Name();                          // identification
  638.    PosGenX(PDF fx) { f=fx; }
  639.    real Density(real x) { return (*f)(x); }
  640. };
  641.  
  642. class SymGenX : public SymGen
  643. {
  644.    PDF f;
  645. public:
  646.    char* Name();                          // identification
  647.    SymGenX(PDF fx) { f=fx; }
  648.    real Density(real x) { return (*f)(x); }
  649. };
  650.  
  651. class AsymGenX : public AsymGen
  652. {
  653.    PDF f;
  654. public:
  655.    char* Name();                          // identification
  656.    AsymGenX(PDF fx, real mode) : (mode) { f=fx; }
  657.    real Density(real x) { return (*f)(x); }
  658. };
  659.  
  660. /***************** discrete random number generator **********************/
  661.  
  662. class DiscreteGen : public Random         // discrete random generator
  663. {
  664.    real *p; int *ialt; int n; real *val;
  665.    void Gen(int, real*);                  // called by constructors
  666.    real mean, var;                        // calculated by the constructor
  667.  
  668. public:
  669.    char* Name();                          // identification
  670.    DiscreteGen(int,real*);                // constructor
  671.    DiscreteGen(int,real*,real*);          // constructor
  672.    ~DiscreteGen();                        // destructor
  673.    real Next();                           // new single value
  674.    ExtReal Mean() { return mean; }
  675.    ExtReal Variance() { return var; }
  676. };
  677.  
  678. /****************** Poisson random number generator *******************/
  679.  
  680. class Poisson : public Random            // generate poisson rv
  681. {
  682.    Random* method;
  683. public:
  684.    char* Name();                          // identification
  685.    Poisson(real);                         // constructor (real=mean)
  686.    ~Poisson() { delete method; }
  687.    real Next() { return method->Next(); }
  688.    ExtReal Mean() { return method->Mean(); }
  689.    ExtReal Variance() { return method->Variance(); }
  690. };
  691.  
  692. /************************* sum of random numbers ************************/
  693.  
  694. class ScaledRandom : public Random
  695. {
  696.    friend Random;
  697.    Random* rv; real s;
  698.    ScaledRandom(ScaledRandom& r) { rv=r.rv; s=r.s; }
  699.    ScaledRandom() {}
  700. public:
  701.    real Next();
  702.    ExtReal Mean();
  703.    ExtReal Variance();
  704. };
  705.  
  706. class ShiftedRandom : public Random
  707. {
  708.    friend Random;
  709.    Random* rv; real s;
  710.    ShiftedRandom(ShiftedRandom& r) { rv=r.rv; s=r.s; }
  711.    ShiftedRandom() {}
  712. public:
  713.    real Next();
  714.    ExtReal Mean();
  715.    ExtReal Variance();
  716. };
  717.  
  718. class RepeatedRandom : public Random
  719. {
  720.    friend Random;
  721.    Random* rv; int n;
  722.    RepeatedRandom(RepeatedRandom& r) { rv=r.rv; n=r.n; }
  723.    RepeatedRandom() {}
  724. public:
  725.    real Next();
  726.    ExtReal Mean();
  727.    ExtReal Variance();
  728. };
  729.  
  730. class AddedRandom : public Random
  731. {
  732.    friend Random;
  733.    Random* rv1; Random* rv2;
  734.    AddedRandom(AddedRandom& r) { rv1=r.rv1; rv2=r.rv2; }
  735.    AddedRandom() {}
  736. public:
  737.    real Next();
  738.    ExtReal Mean();
  739.    ExtReal Variance();
  740.    int nelems();
  741.    void load(int*,real*,Random**);
  742. };
  743.  
  744. class MultedRandom : public Random
  745. {
  746.    friend Random;
  747.    Random* rv1; Random* rv2;
  748.    MultedRandom(MultedRandom& r) { rv1=r.rv1; rv2=r.rv2; }
  749.    MultedRandom() {}
  750. public:
  751.    real Next();
  752.    ExtReal Mean();
  753.    ExtReal Variance();
  754. };
  755.  
  756. class SubtedRandom : public Random
  757. {
  758.    friend Random;
  759.    Random* rv1; Random* rv2;
  760.    SubtedRandom(SubtedRandom& r) { rv1=r.rv1; rv2=r.rv2; }
  761.    SubtedRandom() {}
  762. public:
  763.    real Next();
  764.    ExtReal Mean();
  765.    ExtReal Variance();
  766. };
  767.  
  768. class SumRandom : public Random           // sum of random variables
  769.                                           // version user can use
  770. {
  771.    Random* rv;
  772. public:
  773.    char* Name();                          // identification
  774.    SumRandom(AddedRandom& r) { rv=&r; }
  775.    SumRandom(MultedRandom& r) { rv=&r; }
  776.    SumRandom(SubtedRandom& r) { rv=&r; }
  777.    SumRandom(ShiftedRandom& r) { rv=&r; }
  778.    SumRandom(ScaledRandom& r) { rv=&r; }
  779.    SumRandom(RepeatedRandom& r) { rv=&r; }
  780.    real Next() { return rv->Next(); }
  781.    ExtReal Mean() { return rv->Mean(); }
  782.    ExtReal Variance() { return rv->Variance(); }
  783. };
  784.  
  785. /********************* mixtures of random numbers ************************/
  786.  
  787. class SelectedRandom : public Random
  788. {
  789.    friend Random;
  790.    Random* rv; real p;
  791.    SelectedRandom(SelectedRandom& r) { rv=r.rv; p=r.p; }
  792.    SelectedRandom() {}
  793. public:
  794.    void load(int*,real*,Random**);
  795.    real Next();
  796. };
  797.  
  798. class MixedRandom : public Random         // mixtures of random numbers
  799. {
  800.    int n;                                 // number of components
  801.    DiscreteGen* dg;                       // discrete mixing distribution
  802.    Random** rv;                           // array of pointers to rvs
  803.    ExtReal mean, var;
  804.    void Build(real*);                     // used by constructors
  805.  
  806. public:
  807.    char* Name();                          // identification
  808.    MixedRandom(int, real*, Random**);
  809.    MixedRandom(AddedRandom&);
  810.    ~MixedRandom();
  811.    real Next();
  812.    ExtReal Mean() { return mean; }
  813.    ExtReal Variance() { return var; }
  814. };
  815.  
  816. #endif
  817.  
  818. // random.cxx -----------------------------------------------------------
  819.  
  820.  
  821. typedef double real;                         // all floating point double
  822.  
  823. //#define MONITOR = 0                // monitor constructors and destructors
  824.  
  825. #ifdef ZORTECH
  826.    #include <math.h>
  827.    #include <stdlib.h>
  828.    #include <stream.hpp>
  829. #else
  830.    #include <math.hxx>
  831.    #include <xstream.hxx>
  832.    int rand();
  833. #endif
  834.  
  835. #include <random.hxx>
  836.  
  837. /************ chi-square-1 random number generator **********************/
  838.  
  839. class ChiSq1 : public Normal              // generate non-central chi-square
  840.                                           // rv with 1 degree of freedom
  841. {
  842.    real deltasq;                          // non-centrality parameter
  843.    real delta;
  844.  
  845. public:
  846.    ChiSq1(real);                          // non-centrality parameter
  847.    ExtReal Mean() { return 1.0+deltasq; }
  848.    ExtReal Variance() { return 2.0+4.0*deltasq; }
  849.    real Next();
  850. };
  851.  
  852. /************ Poisson random number generator, larger mu ****************/
  853.  
  854. class Poisson1 : public AsymGen           // generate poisson rv, large mu
  855. {
  856.    real mu, ln_mu;
  857. public:
  858.    Poisson1(real);                        // constructor (real=mean)
  859.    real Density(real);                    // Poisson density function
  860.    real Next();                           // truncate value from AsymGen
  861.    ExtReal Mean() { return mu; }
  862.    ExtReal Variance() { return mu; }
  863. };
  864.  
  865. /*********** Gamma random number generator, alpha <= 1 *****************/
  866.  
  867. class Gamma1 : public PosGen              // generate gamma rv
  868.                                           // shape parameter <= 1
  869. {
  870.    real ln_gam, ralpha, alpha;
  871. public:
  872.    Gamma1(real);                          // constructor (real=shape)
  873.    real Density(real);                    // gamma density function
  874.    real Next();                           // carries out power transform
  875.    ExtReal Mean() { return alpha; }
  876.    ExtReal Variance() { return alpha; }
  877. };
  878.  
  879. /*********** Gamma random number generator, alpha > 1 ******************/
  880.  
  881. class Gamma2 : public AsymGen             // generate gamma rv
  882.                                           // shape parameter > 1
  883. {
  884.    real alpha, ln_gam;
  885. public:
  886.    Gamma2(real);                          // constructor (real=shape)
  887.    real Density(real);                    // gamma density function
  888.    ExtReal Mean() { return alpha; }
  889.    ExtReal Variance() { return alpha; }
  890. };
  891.  
  892. /************ Poisson random number generator, mu <= 10 ****************/
  893.  
  894. class Poisson2 : public Random            // generate poisson rv, large mu
  895. {
  896.    DiscreteGen* dg;
  897. public:
  898.    Poisson2(real);                        // constructor (real=mean)
  899.    ~Poisson2();
  900.    real Next() { return dg->Next(); }
  901.    ExtReal Mean() { return dg->Mean(); }
  902.    ExtReal Variance() { return dg->Variance(); }
  903. };
  904.  
  905. /***************************** utilities ******************************/
  906.  
  907. real ln_gamma(real);                      // log gamma function
  908.  
  909. overload Square;
  910. inline real Square(real x) { return x*x; }
  911. inline ExtReal Square(ExtReal& x) { return x*x; }
  912.  
  913. /************************** end of definitions ************************/
  914.  
  915. real Random::Raw()                           // get new uniform random number
  916. {
  917.    // m = 2147483647 = 2^31 - 1; a = 16807;
  918.    // 127773 = m div a; 2836 = m mod a
  919.    long iseed = (long)seed;
  920.    long hi = iseed / 127773;                 // integer division
  921.    long lo = iseed - hi * 127773;            // modulo
  922.    iseed = 16807 * lo - 2836 * hi;
  923.    if (iseed <= 0) iseed += 2147483647;
  924.    seed = (double)iseed; return seed*4.656612875e-10;
  925. }
  926.  
  927. real Random::Density(real)
  928. { Error("density function not defined"); return 0.0; }
  929.  
  930. real Random::Next()                          // get new mixed random number
  931. {
  932.    int i = rand()/256;                       // 0 <= i < 128
  933.    real f = Buffer[i]; Buffer[i] = Raw();
  934.    return f;
  935. }  
  936.  
  937. double Random::Get()                         // get random number seed
  938. { return seed*4.656612875e-10; }
  939.  
  940. void Random::Set(double s)                   // set random number seed
  941.                                              // s must be between 0 and 1
  942. {
  943.    if (s>=1.0 || s<=0.0) Error("seed out of range");
  944.    seed = (long)(s/4.656612875e-10);
  945.    for (int i = 0; i<128; i++) Buffer[i] = Raw();
  946. }
  947.  
  948. void Random::operator=(Random) { Error("'=' not allowed"); }
  949.  
  950. void Random::Error(char* message)
  951. {
  952.    cerr << "\nError in " << this->Name() << ": " << message << "\n";
  953.    exit(1);
  954. }
  955.  
  956. void Random::ErrorNoSpace()
  957. {
  958.    cerr << "\nError in " << this->Name() << ": no space\n";
  959.    exit(1);
  960. }
  961.  
  962.  
  963. PosGen::PosGen()                             // Constructor
  964. {
  965.    #ifdef MONITOR
  966.       cout << "constructing PosGen\n";
  967.    #endif
  968.    NotReady=TRUE;
  969. }
  970.  
  971. PosGen::~PosGen()
  972. {
  973.    if (!NotReady)
  974.    {
  975.       #ifdef MONITOR
  976.          cout << "freeing PosGen arrays\n";
  977.       #endif
  978.       delete [60] sx; delete [60] sfx;
  979.    }
  980.    #ifdef MONITOR
  981.       cout << "destructing PosGen\n";
  982.    #endif
  983. }
  984.  
  985. void PosGen::Build(BOOL sym)                 // set up arrays
  986. {
  987.    #ifdef MONITOR
  988.       cout << "building PosGen arrays\n";
  989.    #endif
  990.    NotReady=FALSE;
  991.    sx=new real[60]; sfx=new real[60];
  992.    if (!sx || !sfx) ErrorNoSpace();
  993.    real sxi=0.0; real inc = sym ? 0.01 : 0.02;
  994.    for (int i=0; i<60; i++)
  995.    {
  996.       sx[i]=sxi; real f1=Density(sxi); sfx[i]=f1;
  997.       if (f1<=0.0) goto L20;
  998.       sxi+=inc/f1;
  999.    }
  1000.    Error("area too large");
  1001. L20:
  1002.    if (i<50) Error("area too small");
  1003.    xi = sym ? 2*i : i;
  1004.    return;
  1005. }
  1006.  
  1007. real PosGen::Next()
  1008. {
  1009.    real ak,y; int ir;
  1010.    if (NotReady) Build(FALSE);
  1011.    do {
  1012.       real r1=Random::Next();
  1013.       ir = (int)(r1*xi); real sxi=sx[ir];
  1014.       ak=sxi+(sx[ir+1]-sxi)*Random::Next();
  1015.       y=sfx[ir]*Random::Next();
  1016.    } while ( y>=sfx[ir+1] && y>=Density(ak) );
  1017.    return ak;
  1018. }
  1019.  
  1020. real SymGen::Next()
  1021. {
  1022.    real s,ak,y; int ir;
  1023.    if (NotReady) Build(TRUE);
  1024.    do {
  1025.       s=1.0;
  1026.       real r1=Random::Next();
  1027.       if (r1>0.5) { s=-1.0; r1=1.0-r1; }
  1028.       ir = (int)(r1*xi); real sxi=sx[ir];
  1029.       ak=sxi+(sx[ir+1]-sxi)*Random::Next();
  1030.       y=sfx[ir]*Random::Next();
  1031.    } while ( y>=sfx[ir+1] && y>=Density(ak) );
  1032.    return s*ak;
  1033. }
  1034.  
  1035. AsymGen::AsymGen(real modex)                 // Constructor
  1036. {
  1037.    #ifdef MONITOR
  1038.       cout << "constructing AsymGen\n";
  1039.    #endif
  1040.    mode=modex; NotReady=TRUE;
  1041. }
  1042.  
  1043. void AsymGen::Build()                        // set up arrays
  1044. {
  1045.    #ifdef MONITOR
  1046.       cout << "building AsymGen arrays\n";
  1047.    #endif
  1048.    NotReady=FALSE;
  1049.    sx=new real[121]; sfx=new real[121];
  1050.    if (!sx || !sfx)  ErrorNoSpace();
  1051.    real sxi=mode;
  1052.    for (int i=0; i<120; i++)
  1053.    {
  1054.       sx[i]=sxi; real f1=Density(sxi); sfx[i]=f1;
  1055.       if (f1<=0.0) goto L20;
  1056.       sxi+=0.01/f1;
  1057.    }
  1058.    Error("area too large (a)");
  1059. L20:
  1060.    ic=i-1; sx[120]=sxi; sfx[120]=0.0;
  1061.    sxi=mode;
  1062.    for (; i<120; i++)
  1063.    {
  1064.       sx[i]=sxi; real f1=Density(sxi); sfx[i]=f1;
  1065.       if (f1<=0.0) goto L30;
  1066.       sxi-=0.01/f1;
  1067.    }
  1068.    Error("area too large (b)");
  1069. L30:
  1070.    if (i<100)  Error("area too small");
  1071.    xi=i;
  1072.    return;
  1073. }
  1074.  
  1075. real AsymGen::Next()
  1076. {
  1077.    real ak,y; int ir1;
  1078.    if (NotReady) Build();
  1079.    do {
  1080.       real r1=Random::Next();
  1081.       int ir=(int)(r1*xi); real sxi=sx[ir];
  1082.       ir1 = (ir==ic) ? 120 : ir+1;
  1083.       ak=sxi+(sx[ir1]-sxi)*Random::Next();
  1084.       y=sfx[ir]*Random::Next();
  1085.    } while ( y>=sfx[ir1] && y>=Density(ak) );
  1086.    return ak;
  1087. }
  1088.  
  1089. AsymGen::~AsymGen()
  1090. {
  1091.    if (!NotReady)
  1092.    {
  1093.       #ifdef MONITOR
  1094.          cout << "freeing AsymGen arrays\n";
  1095.       #endif
  1096.       delete [121] sx; delete [121] sfx;
  1097.    }
  1098.    #ifdef MONITOR
  1099.       cout << "destructing AsymGen\n";
  1100.    #endif
  1101. }
  1102.  
  1103. Normal::Normal()
  1104. {
  1105.    if (count) { NotReady=FALSE; xi=Nxi; sx=Nsx; sfx=Nsfx; }
  1106.    else { Build(TRUE); Nxi=xi; Nsx=sx; Nsfx=sfx; }
  1107.    count++;
  1108. }
  1109.  
  1110. Normal::~Normal()
  1111. {
  1112.    count--;
  1113.    if (count) NotReady=TRUE;                     // disable freeing arrays
  1114. }
  1115.  
  1116. real Normal::Density(real x)                     // normal density
  1117. { return (fabs(x)>8.0) ? 0 : 0.398942280 * exp(-x*x / 2); }
  1118.  
  1119. ChiSq1::ChiSq1(real d) : ()                      // chisquare with 1 df
  1120. { deltasq=d; delta=sqrt(d); }
  1121.  
  1122. real ChiSq1::Next()
  1123. { real z=Normal::Next()+delta; return z*z; }
  1124.  
  1125. ChiSq::ChiSq(int df, real noncen)
  1126. {
  1127.   if (df<=0 || noncen<0.0) Error("illegal parameters");
  1128.   else if (df==1) { version=0; c1=new ChiSq1(noncen); }
  1129.   else if (noncen==0.0)
  1130.   {
  1131.      if (df==2) { version=1; c1=new Exponential(); }
  1132.      else { version=2; c1=new Gamma2(0.5*df); }
  1133.   }
  1134.   else if (df==2) { version=3; c1=new ChiSq1(noncen/2.0); }
  1135.   else if (df==3) { version=4; c1=new Exponential(); c2=new ChiSq1(noncen); }
  1136.   else { version=5; c1=new Gamma2(0.5*(df-1)); c2=new ChiSq1(noncen); }
  1137.   if (!c1 || (version>3 && !c2)) ErrorNoSpace();
  1138.   mean=df+noncen; var=2*df+4.0*noncen;
  1139. }
  1140.  
  1141. ChiSq::~ChiSq() { delete c1; if (version>3) delete c2; }
  1142.  
  1143. real ChiSq::Next()
  1144. {
  1145.    switch(version)
  1146.    {
  1147.    case 0: return c1->Next();
  1148.    case 1: case 2: return c1->Next()*2.0;
  1149.    case 3: return c1->Next() + c1->Next();
  1150.    case 4: case 5: return c1->Next()*2.0 + c2->Next();
  1151.    }
  1152. }
  1153.  
  1154. real Cauchy::Density(real x)                     // Cauchy density function
  1155. { return (fabs(x)>1.0e15) ? 0 : 0.31830988618 / (1.0+x*x); }
  1156.  
  1157. Poisson1::Poisson1(real mux) : (mux)             // Constructor
  1158. { mu=mux; ln_mu=log(mu); }
  1159.  
  1160. real Poisson1::Density(real x)                   // Poisson density function
  1161. {
  1162.    if (x<0.0) return 0.0;
  1163.    double ix = floor(x);                         // use integer part
  1164.    double l = ln_mu * ix - mu - ln_gamma(1.0+ix);
  1165.    return  (l < -30.0) ? 0.0 : exp(l);
  1166. }
  1167.  
  1168. real Poisson1::Next() { return floor(AsymGen::Next()); }
  1169.  
  1170. Poisson2::Poisson2(real mux)
  1171. {
  1172.    real probs[40];
  1173.    probs[0]=exp(-mux);
  1174.    for (int i=1; i<40; i++) probs[i]=probs[i-1]*mux/i;
  1175.    dg=new DiscreteGen(40,probs);
  1176.    if (!dg) ErrorNoSpace();
  1177. }
  1178.  
  1179. Poisson2::~Poisson2() { delete dg; }   
  1180.  
  1181. real Exponential::Density(real x)                // Negative exponential
  1182. { return  (x > 30.0) ? 0.0 : exp(-x); }
  1183.  
  1184. Poisson::Poisson(real mu)
  1185. {
  1186.    if (mu<=10.0) method = new Poisson2(mu);
  1187.    else method = new Poisson1(mu);
  1188.    if (!method) ErrorNoSpace();
  1189. }
  1190.  
  1191. Gamma1::Gamma1(real alphax)                      // constructor (real=shape)
  1192. { ralpha=1.0/alphax; ln_gam=ln_gamma(alphax+1.0); alpha=alphax; }
  1193.  
  1194. real Gamma1::Density(real x)                     // density function for
  1195. {                                                // transformed gamma
  1196.    double l = - pow(x,ralpha) - ln_gam;
  1197.    return  (l < -30.0) ? 0.0 : exp(l);
  1198. }
  1199.  
  1200. real Gamma1::Next()                               // transform variable
  1201. { return pow(PosGen::Next(),ralpha); }
  1202.  
  1203. Gamma2::Gamma2(real alphax) : (alphax-1.0)       // constructor (real=shape)
  1204. { alpha=alphax; ln_gam=ln_gamma(alpha); }
  1205.  
  1206. real Gamma2::Density(real x)                     // gamma density function
  1207. {
  1208.    if (x<=0.0) return 0.0;
  1209.    double l = (alpha-1.0)*log(x) - x - ln_gam;
  1210.    return  (l < -30.0) ? 0.0 : exp(l);
  1211. }
  1212.  
  1213. Gamma::Gamma(real alpha)                         // general gamma generator
  1214. {
  1215.    if (alpha<1.0) method = new Gamma1(alpha);
  1216.    else if (alpha==1.0) method = new Exponential();
  1217.    else method = new Gamma2(alpha);
  1218.    if (!method)  ErrorNoSpace();
  1219. }
  1220.  
  1221. DiscreteGen::DiscreteGen(int n1, real* prob)     // discrete generator
  1222.                                                  // values on 0,...,n1-1
  1223. {
  1224.    #ifdef MONITOR
  1225.       cout << "constructing DiscreteGen\n";
  1226.    #endif
  1227.    Gen(n1, prob); val=0;
  1228.    mean=0.0; var=0.0;
  1229.    { for (int i=0; i<n; i++) mean = mean + i*prob[i]; }
  1230.    { for (int i=0; i<n; i++) var = var + Square(i-mean) * prob[i]; }
  1231. }
  1232.  
  1233. DiscreteGen::DiscreteGen(int n1, real* prob, real* val1)
  1234.                                                  // discrete generator
  1235.                                                  // values on *val
  1236. {
  1237.    #ifdef MONITOR
  1238.       cout << "constructing DiscreteGen\n";
  1239.    #endif
  1240.    Gen(n1, prob); val = new real[n1];
  1241.    if (!val)  ErrorNoSpace();
  1242.    for (int i=0; i<n1; i++) val[i]=val1[i];
  1243.    mean=0.0; var=0.0;
  1244.    { for (int i=0; i<n; i++) mean = mean + val[i]*prob[i]; }
  1245.    { for (int i=0; i<n; i++) var = var + Square(val[i]-mean)*prob[i]; }
  1246. }
  1247.  
  1248.  
  1249. void DiscreteGen::Gen(int n1, real* prob)
  1250. {
  1251.    n=n1;                                         // number of values
  1252.    p=new real[n]; ialt=new int[n];
  1253.    if (!p || !ialt)  ErrorNoSpace();
  1254.    real rn = 1.0/n; real px; int i;
  1255.    for (i=0; i<n; i++) { p[i]=0.0; ialt[i]=-1; }
  1256.    for (i=0; i<n; i++)
  1257.    {
  1258.       real pmin=1.0; real pmax=-1.0; int jmin=-1; int jmax=-1;
  1259.       for (int j=0; j<n; j++)
  1260.       {
  1261.          if (ialt[j]<0)
  1262.          {
  1263.             px=prob[j]-p[j];
  1264.             if (pmax<=px) { pmax=px; jmax=j; }
  1265.             if (pmin>=px) { pmin=px; jmin=j; }
  1266.          }
  1267.       }
  1268.       if ((jmax<0) || (jmin<0)) Error("method fails");
  1269.       ialt[jmin]=jmax; px=rn-pmin; p[jmax]+=px; px*=n; p[jmin]=px;
  1270.       if ((px>1.00001)||(px<-.00001)) Error("probs don't add to 1 (a)");
  1271.    }
  1272.    if (px>0.00001) Error("probs don't add to 1 (b)");
  1273. }
  1274.  
  1275. DiscreteGen::~DiscreteGen()
  1276. {
  1277.    delete [n] p; delete [n] ialt; if (!val) delete [n] val;
  1278.    #ifdef MONITOR
  1279.       cout << "destructing DiscreteGen\n";
  1280.    #endif
  1281. }
  1282.  
  1283. real DiscreteGen::Next()                  // Next discrete random variable
  1284. {
  1285.    int i = (int)(n*Random::Next()); if (Random::Next()<p[i]) i=ialt[i];
  1286.    return val ? val[i] : (real)i;
  1287. }
  1288.  
  1289. real ln_gamma(real xx)
  1290. {
  1291.    // log gamma function from numerical recipies in C
  1292.  
  1293.    if (xx<1.0)                           // Use reflection formula
  1294.    {
  1295.       const double pi=3.14159265359;
  1296.       double piz = pi * (1.0-xx);
  1297.       return log(piz/sin(piz))-ln_gamma(2.0-xx);
  1298.    }
  1299.    else
  1300.    {
  1301.       static double cof[6]={76.18009173,-86.50532033,24.01409822,
  1302.          -1.231739516,0.120858003e-2,-0.536382e-5};
  1303.  
  1304.       double x=xx-1.0; double tmp=x+5.5;
  1305.       tmp -= (x+0.5)*log(tmp); double ser=1.0;
  1306.       for (int j=0;j<=5;j++) { x += 1.0; ser += cof[j]/x; }
  1307.       return -tmp+log(2.50662827465*ser);
  1308.    }
  1309. }
  1310.  
  1311. real ScaledRandom::Next() { return rv->Next()*s; }
  1312.  
  1313. ExtReal ScaledRandom::Mean() { return rv->Mean()*s; }
  1314.  
  1315. ExtReal ScaledRandom::Variance() { return rv->Variance()*(s*s); }
  1316.  
  1317. real ShiftedRandom::Next() { return rv->Next()+s; }
  1318.  
  1319. ExtReal ShiftedRandom::Mean() { return rv->Mean()+s; }
  1320.  
  1321. ExtReal ShiftedRandom::Variance() { return rv->Variance(); }
  1322.  
  1323. ExtReal RepeatedRandom::Mean() { return rv->Mean()*(real)n; }
  1324.  
  1325. ExtReal RepeatedRandom::Variance() { return rv->Variance()*(real)n; }
  1326.  
  1327. RepeatedRandom Random::operator()(int n)
  1328. { RepeatedRandom r; r.rv=this; r.n=n; return r; }
  1329.  
  1330. ShiftedRandom Random::operator+(real s)
  1331. { ShiftedRandom r; r.rv=this; r.s=s; return r; }
  1332.  
  1333. ShiftedRandom Random::operator-(real s)
  1334. { ShiftedRandom r; r.rv=this; r.s=-s; return r; }
  1335.  
  1336. ScaledRandom Random::operator*(real s)
  1337. { ScaledRandom r; r.rv=this; r.s=s; return r; }
  1338.  
  1339. AddedRandom Random::operator+(Random& rv2)
  1340. { AddedRandom r; r.rv1=this; r.rv2=&rv2; return r; }
  1341.  
  1342. MultedRandom Random::operator*(Random& rv2)
  1343. { MultedRandom r; r.rv1=this; r.rv2=&rv2; return r; }
  1344.  
  1345. SubtedRandom Random::operator-(Random& rv2)
  1346. { SubtedRandom r; r.rv1=this; r.rv2=&rv2; return r; }
  1347.  
  1348. real AddedRandom::Next() { return rv1->Next() + rv2->Next() ; }
  1349.  
  1350. ExtReal AddedRandom::Mean() { return rv1->Mean() + rv2->Mean() ; }
  1351.  
  1352. ExtReal AddedRandom::Variance() { return rv1->Variance() + rv2->Variance() ; }
  1353.  
  1354. int AddedRandom::nelems() { return rv1->nelems() + rv2->nelems(); }
  1355.  
  1356. void AddedRandom::load(int* i, real* probs, Random** rvx)
  1357. { rv1->load(i, probs, rvx); rv2->load(i, probs, rvx); }
  1358.  
  1359. real SubtedRandom::Next() { return rv1->Next() - rv2->Next() ; }
  1360.  
  1361. ExtReal SubtedRandom::Mean() { return rv1->Mean() - rv2->Mean() ; }
  1362.  
  1363. ExtReal SubtedRandom::Variance() { return rv1->Variance() + rv2->Variance() ; }
  1364.  
  1365. real MultedRandom::Next() { return rv1->Next() * rv2->Next() ; }
  1366.  
  1367. ExtReal MultedRandom::Mean() { return rv1->Mean() * rv2->Mean() ; }
  1368.  
  1369. ExtReal MultedRandom::Variance()
  1370. {
  1371.    ExtReal e1 = Square(rv1->Mean()); ExtReal e2 = Square(rv2->Mean());
  1372.    ExtReal v1 = rv1->Variance(); ExtReal v2 = rv2->Variance();
  1373.    ExtReal r=v1*v2; r=r+v1*e2; r=r+e1*v2;  // sum doesn't work under Zortech
  1374.    return r;
  1375. }
  1376.  
  1377. void Random::load(int*,real*,Random**) { Error("Illegal combination"); }
  1378.  
  1379. void SelectedRandom::load(int* i, real* probs, Random** rvx)
  1380. { probs[*i]=p; rvx[*i]=rv; (*i)++; }
  1381.  
  1382. real SelectedRandom::Next() { Error("Next not defined"); return 0.0; }
  1383.  
  1384. real RepeatedRandom::Next()
  1385. { real sum=0.0; for (int i=0; i<n; i++) sum+=rv->Next(); return sum; }
  1386.  
  1387. MixedRandom::MixedRandom(int nx, real* probs, Random** rvx)
  1388. {
  1389.    n=nx;
  1390.    rv=new Random*[n]; if (!rv) ErrorNoSpace();
  1391.    for (int i=0; i<n; i++) rv[i]=rvx[i];
  1392.    Build(probs);
  1393. }
  1394.  
  1395. MixedRandom::MixedRandom(AddedRandom& sr)
  1396. {
  1397.    n = sr.nelems();                       // number of terms;
  1398.    real* probs = new real[n]; rv = new Random*[n];
  1399.    if (!probs || !rv) ErrorNoSpace();
  1400.    int i=0;
  1401.    sr.load(&i,probs,rv);
  1402.    Build(probs);
  1403.    delete [n] probs;
  1404. }
  1405.  
  1406. void MixedRandom::Build(real* probs)
  1407. {
  1408.    dg=new DiscreteGen(n,probs);
  1409.    if (!dg) ErrorNoSpace();
  1410.    mean=0.0; var=0.0;
  1411.    for (int i=0; i<n; i++) mean = mean + (rv[i])->Mean()*probs[i];
  1412.    for (i=0; i<n; i++)
  1413.    {
  1414.       ExtReal sigsq=(rv[i])->Variance();
  1415.       ExtReal mudif=(rv[i])->Mean()-mean;
  1416.       var = var + (sigsq+Square(mudif))*probs[i];
  1417.    }
  1418. }
  1419.  
  1420. MixedRandom::~MixedRandom() { delete [n] rv; delete dg; }
  1421.  
  1422. real MixedRandom::Next()
  1423. {
  1424.    int i = (int)(0.5+dg->Next());          // rounding
  1425.    return (rv[i])->Next();
  1426. }
  1427.  
  1428. SelectedRandom Random::operator()(double p)
  1429. { SelectedRandom r; r.rv=this; r.p=p; return r; }
  1430.  
  1431.  
  1432. // Identification routines for each class - may be not work on all compilers
  1433.  
  1434. char* Random::Name()       { return "Random";      }
  1435. char* Constant::Name()     { return "Constant";    }
  1436. char* PosGen::Name()       { return "PosGen";      }
  1437. char* SymGen::Name()       { return "SymGen";      }
  1438. char* AsymGen::Name()      { return "AsymGen";     }
  1439. char* PosGenX::Name()      { return "PosGenX";     }
  1440. char* SymGenX::Name()      { return "SymGenX";     }
  1441. char* AsymGenX::Name()     { return "AsymGenX";    }
  1442. char* Normal::Name()       { return "Normal";      }
  1443. char* ChiSq::Name()        { return "ChiSq";       }
  1444. char* Cauchy::Name()       { return "Cauchy";      }
  1445. char* Exponential::Name()  { return "Exponential"; }
  1446. char* Poisson::Name()      { return "Poisson";     }
  1447. char* Gamma::Name()        { return "Gamma";       }
  1448. char* DiscreteGen::Name()  { return "DiscreteGen"; }
  1449. char* SumRandom::Name()    { return "SumRandom";   }
  1450. char* MixedRandom::Name()  { return "MixedRandom"; }
  1451.  
  1452. // extreal.hxx ----------------------------------------------------------
  1453.  
  1454.  
  1455. #ifndef EXTREAL_LIB
  1456. #define EXTREAL_LIB 0
  1457.  
  1458. /************************ extended real class ***************************/
  1459.  
  1460. enum EXT_REAL_CODE
  1461.    { Finite, PlusInfinity, MinusInfinity, Indefinite, Missing };
  1462.  
  1463. class ExtReal
  1464. {
  1465.    real value;
  1466.    EXT_REAL_CODE c;
  1467. public:
  1468.    ExtReal operator+(ExtReal&);
  1469.    ExtReal operator-(ExtReal&);
  1470.    ExtReal operator*(ExtReal&);
  1471.    ExtReal operator-();
  1472.    friend ostream& operator<<( ostream&, ExtReal& );
  1473.    ExtReal(real v) { c=Finite; value=v; }
  1474.    ExtReal(EXT_REAL_CODE cx) { c=cx; }
  1475.    ExtReal() { c = Missing; }
  1476. };
  1477.  
  1478. #endif
  1479.  
  1480. // extreal.cxx ----------------------------------------------------------
  1481.  
  1482.  
  1483. typedef double real;
  1484.  
  1485. #ifdef ZORTECH
  1486.    #include <stream.hpp>
  1487. #else
  1488.    #include <xstream.hxx>
  1489. #endif
  1490.  
  1491. #include <extreal.hxx>
  1492.  
  1493. ExtReal ExtReal::operator+(ExtReal& er)
  1494. {
  1495.    if (c==Finite && er.c==Finite) return ExtReal(value+er.value);
  1496.    if (c==Missing || er.c==Missing) return ExtReal(Missing);
  1497.    if (c==Indefinite || er.c==Indefinite) return ExtReal(Indefinite);
  1498.    if (c==PlusInfinity)
  1499.    {
  1500.       if (er.c==MinusInfinity) return ExtReal(Indefinite);
  1501.       return *this;
  1502.    }
  1503.    if (c==MinusInfinity)
  1504.    {
  1505.       if (er.c==PlusInfinity) return ExtReal(Indefinite);
  1506.       return *this;
  1507.    }
  1508.    return er;
  1509. }
  1510.  
  1511. ExtReal ExtReal::operator-(ExtReal& er)
  1512. {
  1513.    if (c==Finite && er.c==Finite) return ExtReal(value-er.value);
  1514.    if (c==Missing || er.c==Missing) return ExtReal(Missing);
  1515.    if (c==Indefinite || er.c==Indefinite) return ExtReal(Indefinite);
  1516.    if (c==PlusInfinity)
  1517.    {
  1518.       if (er.c==PlusInfinity) return ExtReal(Indefinite);
  1519.       return *this;
  1520.    }
  1521.    if (c==MinusInfinity)
  1522.    {
  1523.       if (er.c==MinusInfinity) return ExtReal(Indefinite);
  1524.       return *this;
  1525.    }
  1526.    return er;
  1527. }
  1528.  
  1529. ExtReal ExtReal::operator*(ExtReal& er)
  1530. {
  1531.    if (c==Finite && er.c==Finite) return ExtReal(value*er.value);
  1532.    if (c==Missing || er.c==Missing) return ExtReal(Missing);
  1533.    if (c==Indefinite || er.c==Indefinite) return ExtReal(Indefinite);
  1534.    if (c==Finite)
  1535.    {
  1536.       if (value==0.0) return ExtReal(Indefinite);
  1537.       if (value>0.0) return er;
  1538.       return (-er);
  1539.    }
  1540.    if (er.c==Finite)
  1541.    {
  1542.       if (er.value==0.0) return ExtReal(Indefinite);
  1543.       if (er.value>0.0) return *this;
  1544.       return -(*this);
  1545.    }
  1546.    if (c==PlusInfinity) return er;
  1547.    return (-er);
  1548. }
  1549.  
  1550. ExtReal ExtReal::operator-()
  1551. {
  1552.    switch (c)
  1553.    {
  1554.       case Finite:        return ExtReal(-value);
  1555.       case PlusInfinity:  return ExtReal(MinusInfinity);
  1556.       case MinusInfinity: return ExtReal(PlusInfinity);
  1557.       case Indefinite:    return ExtReal(Indefinite);
  1558.       case Missing:       return ExtReal(Missing);
  1559.    }
  1560. }
  1561.  
  1562. ostream& operator<<(ostream& os, ExtReal& er)
  1563. {
  1564.    switch (er.c)
  1565.    {
  1566.       case Finite:        os << er.value;         break;
  1567.       case PlusInfinity:  os << "plus-infinity";  break;
  1568.       case MinusInfinity: os << "minus-infinity"; break;
  1569.       case Indefinite:    os << "indefinite";     break;
  1570.       case Missing:       os << "missing";        break;
  1571.    }
  1572.    return os;
  1573. }
  1574.  
  1575.  
  1576.  
  1577. // boolean.hxx ------------------------------------------------------------
  1578.  
  1579. #ifndef BOOL_LIB
  1580. #define BOOL_LIB 0
  1581.  
  1582. enum BOOL { FALSE, TRUE };
  1583.  
  1584. #endif
  1585.  
  1586.  
  1587. // end ----------------------------------------------------------------------
  1588.